﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GraphDrawing
{
    class Tree
    {
        
        private List<List<Edge>> _possibleTreeList;
        
        private List<Edge> _possibleEdgesList;

        public Tree()
        {

        }

        public Tree(List<Vertex> vertexes)
        {
            PossibleEdges(vertexes);
            PossibleTrees(vertexes);
        }

        public void PossibleEdges(List<Vertex> Vertexes)
        {
            var numberOfVertex = Vertexes.Count;
            var possibleEdges = new int[Convert.ToInt32(Math.Pow(numberOfVertex,2)),2];
            for (var i = 0; i < 2; i++)
            {
                var j = 0;
                do
                {
                    for (var k = 0; k < numberOfVertex; k++)
                    {
                        for (var l = 0; l < Math.Pow(numberOfVertex, i); l++)
                        {
                            if (j < Math.Pow(numberOfVertex,2))
                            {
                                possibleEdges[j, i] = k;
                                j++;
                            }
                            else
                                break;

                        }
                    }
                } while (j < Math.Pow(numberOfVertex,2) - i);
            }

            var enumerator = 0;
            _possibleEdgesList = new List<Edge>();
            for (var i = 0; i < Math.Pow(numberOfVertex,2); i++)
            {
                if (possibleEdges[i,0]!=possibleEdges[i,1])
                {
                    Edge temp = new Edge(Vertexes,possibleEdges[i,0],possibleEdges[i,1]) {edgeId = enumerator};
                    _possibleEdgesList.Add(temp);
                    enumerator++;
                }

            }
            for (int i = 0; i < _possibleEdgesList.Count; i++)
            {
                for (int j = 0; j < _possibleEdgesList.Count; j++)
                {
                    if (_possibleEdgesList[i].v1 == _possibleEdgesList[j].v2 && _possibleEdgesList[i].v2 == _possibleEdgesList[j].v1)
                    {
                        _possibleEdgesList.RemoveAt(i);
                    }
                }
            }
            

        }

        public void PossibleTrees(List<Vertex> vertexes )
        {
            Edge [,] possibleTrees = new Edge [(int) Math.Pow(_possibleEdgesList.Count, vertexes.Count-1),vertexes.Count - 1];
            for (int i = 0; i < vertexes.Count - 1; i++)
            {
                int j = 0;
                do
                {
                    for (int k = 0; k < _possibleEdgesList.Count; k++)
                    {
                        for (int l = 0; l < Math.Pow(_possibleEdgesList.Count, i); l++)
                        {
                            if (j < (int)Math.Pow(_possibleEdgesList.Count, vertexes.Count - 1))
                            {
                                possibleTrees[j, i] = _possibleEdgesList[k];
                                j++;
                            }
                            else
                                break;

                        }
                    }
                } while (j < (int)Math.Pow(_possibleEdgesList.Count, vertexes.Count - 1) - i);

            }
            _possibleTreeList = new List<List<Edge>>();
            for (int i = 0; i < (int)Math.Pow(_possibleEdgesList.Count, vertexes.Count - 1); i++)
            {
                List<Edge> tempList = new List<Edge>();
                List<Edge> sortedTempList = new List<Edge>();
                for (int j = 0; j < vertexes.Count-1; j++)
                {
                    tempList.Add(possibleTrees[i,j]);
                }
                sortedTempList = tempList.OrderBy(q => q.edgeId).ToList();
                _possibleTreeList.Add(sortedTempList);
            }
            ////////////////////////////usuwanie drzew z powtarzajacymi sie krawedziami
            for (int l = 0; l < _possibleTreeList.Count; l++)
            {
                 for (int i = 0; i < _possibleTreeList.Count; i++)
                {
                    bool fail = false;
                    for (int j = 0; j < vertexes.Count - 1; j++)
                    {
                        for (int k = 0; k < vertexes.Count - 1; k++)
                        {
                            if (_possibleTreeList[i][j].edgeId == _possibleTreeList[i][k].edgeId && j != k)
                            {
                                fail = true;
                            }

                        }
                    }
                    if (fail)
                    {
                        _possibleTreeList.RemoveAt(i);

                    }
                }
            }
           
            ////////////////////////////usuwanie takich samych drzew
            for (int k = 0; k < _possibleTreeList.Count; k++)
            {
                for (int i = 0; i < _possibleTreeList.Count; i++)
                {
                    string test = getTreeEdges(_possibleTreeList[i]);
                    for (int j = 0; j < _possibleTreeList.Count; j++)
                    {
                        string test2 = getTreeEdges(_possibleTreeList[j]);
                        if (test == test2 && i != j)
                        {
                            _possibleTreeList.RemoveAt(i);
                            break;
                        }
                    }


                }
            }

            ///////////////////////////dla wierzcholkow > 3, usuwanie blednych drzew
            if (vertexes.Count > 3)
            {
                for (int l = 0; l < _possibleTreeList.Count; l++)
                {
                    for (int i = 0; i < _possibleTreeList.Count; i++)
                    {
                        bool[] fail = new bool[vertexes.Count];
                        for (int j = 0; j < vertexes.Count; j++)
                        {

                            for (int k = 0; k < vertexes.Count - 1; k++)
                            {
                                if (_possibleTreeList[i][k].v1 == j || _possibleTreeList[i][k].v2 == j)
                                {
                                    fail[j] = true;
                                }

                            }

                        }
                        foreach (bool b in fail)
                        {
                            if (!b)
                            {
                                _possibleTreeList.RemoveAt(i);
                                break;
                            }
                        }
                    }
                }
            }

            if (vertexes.Count > 4)
            {
                for (int l = 0; l < _possibleTreeList.Count; l++)
                {
                    for (int i = 0; i < _possibleTreeList.Count; i++)
                    {
                        for (int j = 0; j < vertexes.Count-1; j++)
                        {
                            int checkV1 = 0;
                            int checkV2 = 0;
                            for (int k = 0; k < vertexes.Count-1; k++)
                            {
                                if (_possibleTreeList[i][j].v1 == _possibleTreeList[i][k].v1 || _possibleTreeList[i][j].v1 == _possibleTreeList[i][k].v2 && j != k)
                                checkV1++;
                                
                                if (_possibleTreeList[i][j].v2 == _possibleTreeList[i][k].v2 || _possibleTreeList[i][j].v2 == _possibleTreeList[i][k].v1 && j != k)
                                checkV2++;
                                
                            }
                            if (checkV1 == 1 && checkV2 == 1)
                            {
                                _possibleTreeList.RemoveAt(i);
                                break;
                            }
                        }

                    }
                }

                
            }
           
            
           
          
            
        }
        private string getTreeEdges(List<Edge> tree)
        {
            string edges = null;
            foreach (Edge edge in tree)
            {
                edges +=  edge.edgeId.ToString();
            }
            return edges;
        }

        public List<List<Edge>> GetTrees()
        {
            return _possibleTreeList;
        }
    }
}
